package com.le.tester.webpage.redis.service.impl;

import com.le.tester.common.enums.RedisKey;
import com.le.tester.common.enums.ResponseCode;
import com.le.tester.handler.BusinessException;
import com.le.tester.utils.RedisUtil;
import com.le.tester.utils.SmsUtil;
import com.le.tester.webpage.redis.service.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * 描述：redis的实现类
 */
@Service
public class RedisServiceImpl implements RedisService {

    @Resource
    private RedisUtil redisUtil;

    @Autowired
    private Environment env;

    @Override
    public void sendAuthCode(String mobile) {
        Map<String, Object> resultMap = this.validateMobile(mobile);
        if (resultMap.get("status").equals(ResponseCode.ERROR.getCode())) {
            //throw new RuntimeException(String.valueOf(resultMap.get("msg") + ";" + resultMap.get("code")));
            throw new BusinessException(resultMap.get("code"));
        }

        String code = SmsUtil.getCode();
        //发送自己生成的短信验证码
        //SmsResponse smsResponse = this.sendSmsCode(mobile, code);
        this.writeCache(mobile, code);
    }

    /**
     * 写进redis缓存
     *
     * @param mobile
     * @param code
     */
    @SuppressWarnings("all")
    private void writeCache(String mobile, String code) {
        //设置key值
        BoundValueOperations<String, Object> smsKey = redisUtil.boundValueOps(mobile + RedisKey.SMS_VALIDATE_CODE.getCode());
        smsKey.set(code, 2 * 60, TimeUnit.SECONDS);

        //设置hashKey
        BoundHashOperations<String, Object, Object> hashOps = redisUtil.boundHashOps(mobile + RedisKey.SMS_RECORD.getCode());
        //间隔时间
        hashOps.put(RedisKey.SMS_LAST_TIME.getCode(), String.valueOf(System.currentTimeMillis()));
        //次数(序列化还是使用GenericJackson2JsonRedisSerializer，这个不要去更改，然后类型的装换还是在java处理)
        //这边要累加次数，这样做是可以的
        if (!hashOps.hasKey(RedisKey.SMS_COUNT.getCode())) {
            hashOps.put(RedisKey.SMS_COUNT.getCode(),Integer.parseInt(String.valueOf(BigDecimal.ZERO)));
        }
        hashOps.increment(RedisKey.SMS_COUNT.getCode(), 1);
        if (hashOps.getExpire() == -1) {
            hashOps.expireAt(this.getExpireTime());
        }

    }

    private Date getExpireTime() {
        //加上一天
        LocalDateTime expireTime = LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
//        Original Date: Fri Jul 12 06:01:49 UTC 1996
//        Instant: 1996-07-12T06:01:49.766Z
        Instant instant = expireTime.atZone(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    //验证手机号，逻辑验证
    private Map<String, Object> validateMobile(String mobile) {
        Map<String, Object> resultMap = new HashMap<>();
        /**
         * 验证该用户是不是黑名单;返回0表示不是黑名单用户，1表示是黑名单用户
         */
//        int rowCount = blacklistService.getByMobile(mobile);
//        if (rowCount > 0) {
//            //手机号码被限制了
//            resultMap.put("success", false);
//            resultMap.put("msg", "该手机号码已经被限制！");
//            return resultMap;
//        }
        /**
         * 验证是不是当天第一次发送
         */
        if (!redisUtil.hasKey(mobile + RedisKey.SMS_RECORD.getCode())) {
            resultMap.put("code", ResponseCode.SMS_FIRST_DAY.getCode());
            resultMap.put("msg", ResponseCode.SMS_FIRST_DAY.getDesc());
            resultMap.put("status", ResponseCode.SUCCESS.getCode());
            return resultMap;
        }
        /**
         * 验证发送的次数，一天只能发送次数(存在hashKey中)
         */
        BoundHashOperations<String, Object, Object> hashOps = redisUtil.boundHashOps(mobile + RedisKey.SMS_RECORD.getCode());
        int count = Integer.parseInt(String.valueOf(hashOps.get(RedisKey.SMS_COUNT.getCode())));

        //获取每天发送的最大次数
        int smsTimeNum = Integer.parseInt(String.valueOf(env.getProperty("sms.time.num")));
        if (count >= smsTimeNum) {
            resultMap.put("code", ResponseCode.SMS_TIME_NUM_LIMIT.getCode());
            resultMap.put("msg", ResponseCode.SMS_TIME_NUM_LIMIT.getDesc());
            //全局状态
            resultMap.put("status", ResponseCode.ERROR.getCode());
            return resultMap;
        }
        //间隔时间的限制
        long smsLastTime = Long.parseLong(String.valueOf(hashOps.get(RedisKey.SMS_LAST_TIME.getCode())));
        long intervalSec = (System.currentTimeMillis() - smsLastTime) / 1000;
        //获取自定义的间隔时间
        long intervalTimeLimit = Long.parseLong(String.valueOf(env.getProperty("sms.interval.time")));
        if (intervalSec > intervalTimeLimit) {
            resultMap.put("status", ResponseCode.SUCCESS.getCode());
        } else {
            resultMap.put("code", ResponseCode.SMS_INTERVAL_TIME_LIMIT.getCode());
            resultMap.put("msg", ResponseCode.SMS_INTERVAL_TIME_LIMIT.getDesc());
            resultMap.put("status", ResponseCode.ERROR.getCode());
        }
        return resultMap;
    }

    //验证手机号码;11位并且是1开头的
    @Override
    public boolean checkedPhoneCode(String mobile) {
        //手机号码为空
        if (StringUtils.isBlank(mobile)) {
            return false;
        }
        //匹配1开头并且是11位
        String regex = "^1\\d{10}$";
        return Pattern.matches(regex, mobile);
    }
}
